#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <setjmp.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdbool.h>

#include <rte_common.h>
#include <rte_log.h>
#include <rte_malloc.h>
#include <rte_memory.h>
#include <rte_memcpy.h>
#include <rte_eal.h>
#include <rte_launch.h>
#include <rte_cycles.h>
#include <rte_prefetch.h>
#include <rte_lcore.h>
#include <rte_per_lcore.h>
#include <rte_branch_prediction.h>
#include <rte_interrupts.h>
#include <rte_random.h>
#include <rte_debug.h>
#include <rte_ether.h>
#include <rte_ethdev.h>
#include <rte_mempool.h>
#include <rte_mbuf.h>
#include <rte_string_fns.h>
#include "sender_forward.h"


extern uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
extern struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
extern volatile bool force_quit;
extern rte_spinlock_t g_lock;
struct lcore_queue_stat lcore_queue_stat[RTE_MAX_LCORE];
static struct flow_info flowmap[2];//流表，从s1发来的包属于f1,从s2发来的包属于f2.

static void
fill_ethernet_header(struct rte_ether_hdr *hdr, struct rte_ether_hdr *data_hdr)
{
	// struct rte_ether_addr s_addr = {{0xa4, 0xbf, 0x01, 0x6e, 0xcc, 0xef}}; //s2的mac
	// struct rte_ether_addr d_addr = {{0xe4, 0x3d, 0x1a, 0xac, 0xc8, 0x04}};//switch eno1np0的mac地址
    //dstaddr=192.168.2.217的mac了A4:BF:01:6E:D3:0F
    //srcaddr=192.168.0.218的mac了 A4:BF:01:6E:A6:7A
	//192.168.1.219的mac地址为：A4:BF:01:6E:CC:EF
    //192.168.63.221 的eno2np0 e4:3d:1a:ac:c8:04
    //192.168.63.221 的eno2np1  e4:3d:1a:ac:c8:05
	hdr->src_addr = data_hdr->dst_addr;//mac地址互换
	hdr->dst_addr = data_hdr->src_addr;//mac地址互换
	hdr->ether_type = rte_cpu_to_be_16(0x0800);
}

static void
fill_ipv4_header(struct rte_ipv4_hdr *hdr,struct rte_ipv4_hdr *data_hdr)
{
	hdr->version_ihl = (4 << 4) + 5;		  // ipv4, length 5 (*4)
	hdr->type_of_service = 0x03;			  // No Diffserv
	hdr->total_length = rte_cpu_to_be_16(1440); // tcp 20
	hdr->packet_id = rte_cpu_to_be_16(5462);  // set random
	hdr->fragment_offset = rte_cpu_to_be_16(0);
	hdr->time_to_live = 64;
	hdr->next_proto_id = 6; // tcp
	hdr->hdr_checksum = rte_cpu_to_be_16(25295);

	// hdr->src_addr = rte_cpu_to_be_32(0xC0A801DB); // 192.168.1.219
	// hdr->dst_addr = rte_cpu_to_be_32(0xC0A802D9); // 192.168.2.217
    hdr->src_addr = data_hdr->dst_addr;//ip互换
    hdr->dst_addr = data_hdr->src_addr;//ip互换
    
}

static void
fill_tcp_header(struct rte_tcp_hdr *hdr)
{
	hdr->src_port = rte_cpu_to_be_16(0x162E);
	hdr->dst_port = rte_cpu_to_be_16(0x04d2);
	hdr->sent_seq = rte_cpu_to_be_32(0x0);
	hdr->recv_ack = rte_cpu_to_be_32(0);
	hdr->data_off = 0x50;
	hdr->tcp_flags = 0;
	hdr->rx_win = rte_cpu_to_be_16(16);
	hdr->cksum = rte_cpu_to_be_16(0);
	hdr->tcp_urp = rte_cpu_to_be_16(0);
}

static uint8_t check_mbuf(struct rte_mbuf *m){
    //源和目的ip地址
    rte_be32_t src_addr;

	struct rte_ether_hdr *eth_hdr;
	struct rte_ipv4_hdr *ipv4_hdr;

    eth_hdr = rte_pktmbuf_mtod(data_m, struct rte_ether_hdr *); //解析第一个数据包
	ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1);

    src_addr=rte_be_to_cpu_32(ipv4_hdr->src_addr);
    if(src_addr==0xc0a801db || src_addr==0xc0a800da){//如果是从s1或者s2发来的包，是我们的目的包
        return 1;
    }
    return 0;
}

static void init_raw_pkt(struct rte_mbuf *m, struct rte_mbuf *data_m)
{
    /**
     * 解析数据包的源ip,目的ip,源mac, 目的mac,ecn等信息
     * 
     */
    //源和目的mac地址
    struct rte_ether_addr s_mac;
    struct rte_ether_addr d_mac;

    //源和目的ip地址
    rte_be32_t src_addr;
    rte_be32_t dst_addr;

	struct rte_ether_hdr *eth_hdr;
	struct rte_ipv4_hdr *ipv4_hdr;

    eth_hdr = rte_pktmbuf_mtod(data_m, struct rte_ether_hdr *); //解析第一个数据包
	ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1);


    /**
     * 根据解析的数据包信息构造ack数据帧
     */

	//构造数据域
	struct rte_ether_hdr *ack_ether_h;
	struct rte_ipv4_hdr *ack_ipv4_h;

	// 以太帧
	ack_ether_h = (struct rte_ether_hdr *)rte_pktmbuf_append(m, sizeof(struct rte_ether_hdr));
	fill_ethernet_header(ack_ether_h, eth_hdr);

	// ipv4
	ack_ipv4_h = (struct rte_ipv4_hdr *)rte_pktmbuf_append(m, sizeof(struct rte_ipv4_hdr));
	fill_ipv4_header(ack_ipv4_h,ipv4_hdr);
}


//获取bset的bit_cnt位是0还是1
static uint8_t get_bset_bit(uint8_t bset, uint32_t bit_cnt){
    uint8_t mask = 0x01<<(6-bit_cnt);//注意，这里我是把最高位按下标0开始计算，反过来了。
    return (bset&mask)>>bit_cnt;
}


static uint32_t get_qlen(){
    return (lcore_queue_stat[0].qlen+ lcore_queue_stat[1].qlen);//返回的是包的个数
}


static uint32_t get_flow_max_qlen(uint32_t flow_id){
    uint32_t res = 0;
    for(int i = 0; i<7;i++){
        res = flowmap[flow_id].qlen[i]>res?flowmap[flow_id].qlen[i]:res;
    }
    return res;
}

static uint32_t get_flow_min_qlen(uint32_t flow_id){
    uint32_t res = 0x0fffffff;
    for(int i = 0; i<7;i++){
        res = flowmap[flow_id].qlen[i]<res?flowmap[flow_id].qlen[i]:res;
    }
    return res;
}

static double get_flow_max_txrate(uint32_t flow_id){
    double res = 0x0;
    for(int i = 0; i<7;i++){
        res = flowmap[flow_id].tx_rate[i]>res?flowmap[flow_id].tx_rate[i]:res;
    }
    return res;
}

static inline void update_packet_mac(struct rte_ether_hdr *eth)
{
    //struct rte_ether_hdr *eth;
	void *tmp;
    //dstaddr=192.168.2.217的mac了A4:BF:01:6E:D3:0F
    struct rte_ether_addr d_addr = {{0xa4, 0xbf, 0x01, 0x6e, 0xd3, 0x0f}};
    eth->dst_addr = d_addr;
}


int is_need_fix_dst_port(struct rte_mbuf *m, unsigned portid,unsigned *dst_port)
{
    rte_be32_t src_addr;
    struct rte_ether_hdr *eth;
    if(portid==NEED_FORWARD_PORTID)//需要转发的端口是虚拟交换机的端口0
    {
        return 1;
    }
    
    eth=rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
    rte_pktmbuf_adj(m, (uint16_t)sizeof(struct rte_ether_hdr));
    if (RTE_ETH_IS_IPV4_HDR(m->packet_type)) {
		struct rte_ipv4_hdr *ip_hdr;
		uint32_t ip_dst;
		/* Read the lookup key (i.e. ip_dst) from the input packet */
		ip_hdr = rte_pktmbuf_mtod(m, struct rte_ipv4_hdr *);
        src_addr=rte_be_to_cpu_32(ip_hdr->src_addr);
		if(src_addr==DONT_NEED_FORWARD_IP) //如果源ip地址是来事receiver(192.168.2.217)的包，则进行将目的端口换为源端口
        {
            *dst_port=portid;
            update_packet_mac(eth);
        }
    }
    return 1;
}

static inline uint64_t calc_total_send()
{
    int total_count;
    
    total_count+=lcore_queue_stat[0].packet_count;
    total_count+=lcore_queue_stat[1].packet_count;
    return total_count;
}

static inline void reset_total_send_packet(void)
{
    lcore_queue_stat[0].packet_count=1;
    lcore_queue_stat[1].packet_count=1;
}

static inline uint64_t first_packet_time()
{
    uint64_t tmp;
    uint32_t i;
    
    i=(!lcore_queue_stat[0].first_packet_tsc)?1:0;
    tmp=lcore_queue_stat[i].first_packet_tsc;
    lcore_queue_stat[i].first_packet_tsc=0;
    
    return tmp;

}

uint64_t calc_tx_rate(double timeval,uint64_t packet_byte)
{
    uint64_t tx_rate;
    tx_rate=(uint64_t)(packet_byte/timeval);
}


double calc_timeval(uint64_t first_tsc,uint64_t cur_tsc)
{
    double interval=(cur_tsc-first_tsc)/(double)rte_get_tsc_hz();
    return interval;
}

/*
pkt_len:单个包的数据大小(byte)
*/
void calc_send_packet_stat(uint64_t pkt_len)
{
    uint64_t toatal_send_packet;
    uint64_t first_tsc;
    uint64_t cur_tsc;
    double timeval;
    double interval;
    
    toatal_send_packet=calc_total_send();
    
    if(toatal_send_packet>=100)
    {
        rte_spinlock_lock(&g_lock);
        toatal_send_packet=calc_total_send();
        reset_total_send_packet();
        first_tsc=first_packet_time();
        cur_tsc=rte_rdtsc();
        rte_spinlock_unlock(&g_lock);
        printf("\n");
        timeval=calc_timeval(first_tsc,cur_tsc);
        calc_tx_rate(timeval,pkt_len);
        		// printf("thoughtput out: %f %f\n", cur_time, (tp_meter->intvl_num_bits / interval) / 1e6);
        printf("toatal_send_packet is %21"PRIu64
                "\ntimeval is %lf, txRate is: %f, qlen:%d",
                toatal_send_packet,
                timeval,((toatal_send_packet*pkt_len*8.0)/timeval)/1e6, (uint32_t)(lcore_queue_stat[0].qlen+ lcore_queue_stat[1].qlen));
        printf("\n");
    }
}

/**
 * @brief 更新流的状态信息
 * 
 * @param flow_id 流id
 * @param last_ecn 上一次的ecn状态
 * @param is_same 是否发生了状态切换
 */
static void update_flow_info(uint32_t flow_id,uint8_t last_ecn,bool is_same){
    if(is_same){
        flowmap[flow_id].bit_cnt++;
    }else{
        flowmap[flow_id].bit_cnt = 0;
        flowmap[flow_id].bset = 0;
    }

    flowmap[flow_id].last_ecn_type = last_ecn;

    //计算交换机目前的发送速率
    uint64_t cur_tsc;
    cur_tsc=rte_rdtsc();//当前的tsc
    uint64_t time_gap = (cur_tsc - flowmap[flow_id].last_deq_tsc);//以tsc为单位
    uint64_t tx_bytes_gap = (lcore_queue_stat[0].tx_bytes + lcore_queue_stat[1].tx_bytes) - flowmap[flow_id].tx_bytes;//总的字节数
    double txRate = (tx_bytes_gap * 8 * 1.0 * rte_get_tsc_hz() / time_gap)/1e6;//计算传输速率,最后单位Mbps
    
    flowmap[flow_id].tx_rate[flowmap[flow_id].tq_cnt] = txRate;//保存链路传输速率
    flowmap[flow_id].qlen[flowmap[flow_id].tq_cnt] = get_qlen();//保存队列长度大小

    flowmap[flow_id].tq_cnt = (flowmap[flow_id].tq_cnt + 1) % 7;
    flowmap[flow_id].last_deq_tsc = cur_tsc;
    flowmap[flow_id].tx_bytes = (lcore_queue_stat[0].tx_bytes + lcore_queue_stat[1].tx_bytes);
}

static void mark_packet_ecn(struct rte_mbuf *m, uint8_t ecn){
    struct rte_ether_hdr *eth_hdr;
	struct rte_ipv4_hdr *ipv4_hdr;
    
    eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); //解析第一个数据包
	ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1);
    ipv4_hdr->type_of_service = (ipv4_hdr->type_of_service & 0xfc) | ecn; //ecn 在TOS字段的最后两位
}

/**
 * @brief 交换机真正进行ecn编码部分
 * 
 * @param m 
 * @param flow_id 
 */
static void encoding_ecn(struct rte_mbuf *m, uint32_t flow_id){
    uint8_t curr_should_mark = 0x04;
    if(get_qlen()>10){ //如果当前队列数据包的长度大于10，则进入队列长度编码
        if(flowmap[flow_id].last_ecn_type != 0x03){//状态不一样
            update_flow_info(flow_id,0x03,false);
            curr_should_mark = 0x03;
        }else{//是同样的状态
            if(flowmap[flow_id].bit_cnt==0 || flowmap[flow_id].bit_cnt>6){
                flowmap[flow_id].bset = 0;
                flowmap[flow_id].bit_cnt = 0;
                uint32_t currQlen = get_flow_max_qlen(flow_id);//包的个数，我们最多编码1270个包
                currQlen = currQlen>1270?1270:currQlen;
                flowmap[flow_id].bset = currQlen/10;
            }
            if(get_bset_bit(flowmap[flow_id].bset,flowmap[flow_id].bit_cnt)==0x01){//注意，是从从最高位开始编
                curr_should_mark = 0x03;
            }else{
                curr_should_mark = 0x01;
            }
            update_flow_info(flow_id, 0x03, true);
        }
    }else{//进行链路利用率的编码
        if(flowmap[flow_id].last_ecn_type != 0x02){//状态不一样
            update_flow_info(flow_id,0x02,false);
            curr_should_mark = 0x02;
        }else{//是相同状态
            if(flowmap[flow_id].bit_cnt==0 || flowmap[flow_id].bit_cnt>6){
                flowmap[flow_id].bset = 0;
                flowmap[flow_id].bit_cnt = 0;
                double tx_rate = get_flow_max_txrate(flow_id);
                uint32_t frac = (uint32_t)(100.0*tx_rate/10000);//以10Gbps为带宽
                frac = frac>100?100:frac;
                flowmap[flow_id].bset = frac;
            }
            if(get_bset_bit(flowmap[flow_id].bset,flowmap[flow_id].bit_cnt)==0x01){//注意，是从从最高位开始编
                curr_should_mark = 0x02;
            }else{
                curr_should_mark = 0x01;
            }
            update_flow_info(flow_id, 0x02, true);
        }
    }

    if(curr_should_mark == 0x04){
        printf("ERROR! ecn should not be 0x04!");
        return;
    }
    mark_packet_ecn(m, curr_should_mark);
    

}

/*
更新数据包信息，返回相应的出端口, 该函数暂时不用，暂时先保留该函数
*/
static unsigned update_pkt(struct rte_mbuf *m){
    unsigned dst_port;

    rte_be32_t src_addr;
    rte_be32_t dst_addr;

    struct rte_ether_hdr *eth_hdr;
	struct rte_ipv4_hdr *ipv4_hdr;
    
    eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); //解析第一个数据包
	ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1);
    
    src_addr=rte_be_to_cpu_32(ipv4_hdr->src_addr);
    dst_addr=rte_be_to_cpu_32(ipv4_hdr->dst_addr);

    uint32_t flow_id = 3;

    /*
    判断是数据包还是ack包，从s1,s2来的都是数据包，从r1来的包都是ack包。根据目的地替换mac地址
    */
    if(src_addr == 0xC0A802D9){ //如果源ip是192.168.2.217 (即源ip为r1), ack包
        if(dst_addr == 0xC0A800DA){//目的ip为192.168.0.218 (即s1)
            dst_port = 1;
            struct rte_ether_addr d_addr = {{0xa4, 0xbf, 0x01, 0x6e, 0xa6, 0x7a}};//设置目的mac地址为s1:A4:BF:01:6E:A6:7A
            eth_hdr->dst_addr = d_addr;
        }else if(dst_addr == 0xC0A801DB){//目的ip为192.168.1.219 (即s2)
            dst_port = 0;
            struct rte_ether_addr d_addr = {{0xa4, 0xbf, 0x01, 0x6e, 0xcc, 0xef}};//设置目的mac地址为s2:A4:BF:01:6E:CC:EF
            eth_hdr->dst_addr = d_addr;
        }
    }else if(src_addr == 0xC0A800DA){ //如果源ip是192.168.0.218 (即源ip为s1),数据包
        dst_port = 0;
        struct rte_ether_addr d_addr = {{0xa4, 0xbf, 0x01, 0x6e, 0xd3, 0x0f}};//设置目的mac地址为r1:A4:BF:01:6E:D3:0F
        eth_hdr->dst_addr = d_addr;
        flow_id = 0;
    }else if(src_addr == 0xC0A801DB){ //如果源ip是192.168.1.219 （即源ip为s2）,数据包
        dst_port = 0;
        struct rte_ether_addr d_addr = {{0xa4, 0xbf, 0x01, 0x6e, 0xd3, 0x0f}};//设置目的mac地址为r1:A4:BF:01:6E:D3:0F
        eth_hdr->dst_addr = d_addr;
        flow_id = 1;
    }else{
        printf("ERROR unknow source ip:%x\n",src_addr);
        rte_pktmbuf_free(m);
        dst_port = 3;//目的端口从1发出去
        return 3; //不是我们的目的包，直接drop掉
    }

    if(dst_port == 0){ //如果是从0端口发出去的，修改源mac地址为
        struct rte_ether_addr s_mac = {{0xe4, 0x3d, 0x1a, 0xac, 0xc8, 0x04}};//设置为交换机口0的mac [e4:3d:1a:ac:c8:04]
        eth_hdr->src_addr = s_mac;
    }else{
        struct rte_ether_addr s_mac = {{0xe4, 0x3d, 0x1a, 0xac, 0xc8, 0x05}};//设置为交换机口1的mac [e4:3d:1a:ac:c8:05]
        eth_hdr->src_addr = s_mac;
    }

    if(flow_id == 0|| flow_id == 1){
        encoding_ecn(m,flow_id);//如果不是ack包，则进行一次ECN编码
    }

    return dst_port;
}

static void 
l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid,unsigned lcore_id)
{
    unsigned dst_port;
    int sent;
    //unsigned lcore_id;
    
    // dst_port = l2fwd_dst_ports[portid];//这个地方应该是不对的。
    
    // //这个先不用updatemac了
    // //l2fwd_mac_updating(m, dst_port);
    // is_need_fix_dst_port(m,portid,&dst_port);
    // printf("src:%x,dst:%x,dst_port:%d,dst_mac:",src_addr,dst_addr,dst_port);
    // for(int i=0;i<6;i++){
    //     printf("%x ",eth_hdr->dst_addr.addr_bytes[i]);
    // }
    // printf("\n");

    dst_port = update_pkt(m);//经过交换机，更新交换机信息
    if(dst_port!=0 || dst_port!=1){//异常数据包，直接丢包
        return;
    }
    if(lcore_id != rte_get_main_lcore())
        rte_spinlock_lock(&g_lock);//对非主核加锁，用于统计数据用
    sent = rte_eth_tx_burst(dst_port, 0, &m, 1); //真正的转发数据包。
    if(lcore_id != rte_get_main_lcore())
        rte_spinlock_unlock(&g_lock);
    if (unlikely(sent < 1)) {
        printf("send packet is error\n");
        return;
	}

    lcore_queue_stat[lcore_id].tx_bytes += m->pkt_len;
    lcore_queue_stat[lcore_id].qlen--;

    if(!lcore_queue_stat[0].first_packet_tsc&&!lcore_queue_stat[1].first_packet_tsc)
    {
        lcore_queue_stat[lcore_id].first_packet_tsc=rte_rdtsc();//记录第一个数据包的时钟数
    }
    lcore_queue_stat[lcore_id].packet_count++;
    //printf("send packet is ok\n");
    return ;
}


/* main processing loop */
void l2fwd_switch_main_loop(struct rte_mempool *pool)
{
	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
    struct rte_mbuf *pkts_sned_burst[SEN_PACKET_BRUST];
	struct rte_mbuf *data_m;
    bool flag=false;
	int sent;
	unsigned lcore_id;
	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
	unsigned i, j, portid, nb_rx;
	struct lcore_queue_conf *qconf;
	struct rte_eth_dev_tx_buffer *buffer;

	prev_tsc = 0;
	timer_tsc = 0;

	lcore_id = rte_lcore_id();
	qconf = &lcore_queue_conf[lcore_id];

	if (qconf->n_rx_port == 0) {
		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
		return;
	}

	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);

	for (i = 0; i < qconf->n_rx_port; i++) {

		portid = qconf->rx_port_list[i];
		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
			portid);
	}
    
    uint32_t sent;
    while (!force_quit) {
        
        for (i = 0; i < qconf->n_rx_port; i++) {
            sent = 0;
			portid = qconf->rx_port_list[i];
            nb_rx = rte_eth_rx_burst(portid, 0,
						 pkts_burst, MAX_PKT_BURST);//从两个不同的核中收到了数据包。最大128个包的空间
            lcore_queue_stat[lcore_id].qlen+=nb_rx;
			for (j = 0; j < nb_rx; j++) {//收到数据直接转发
                data_m = pkts_burst[j];
                rte_prefetch0(rte_pktmbuf_mtod(data_m, void *));
                // if(!check_mbuf(data_m)){
                //     rte_pktmbuf_free(data_m);//释放内存
                //     continue;
                // }
                
                // struct rte_mbuf *ack_mbuf;
                // ack_mbuf = rte_pktmbuf_alloc(pool);
                // init_raw_pkt(ack_mbuf, data_m);//初始化ack
                // encoding_ecn(ack_mbuf, (uint32_t)(portid));//编码模块，根据来的端口区分流

                // sent = rte_eth_tx_burst(portid, 0, &ack_mbuf, 1); //转发ACK，从哪个端口来的数据包就从哪个端口转发ack;
                // if (unlikely(sent < 1)) {
                //     printf("[Error] send packet error\n");
                // }
                // rte_pktmbuf_free(data_m);
                // rte_pktmbuf_free(ack_mbuf);
				l2fwd_simple_forward(data_m, portid,lcore_id); //转发数据包逻辑

                // if (lcore_id == rte_get_main_lcore()) //如果是主核(主核id为0)，那么统计数据量
                // {
                //     calc_send_packet_stat(data_m->pkt_len);
                // }
			}
		}
    }
}


